package com.yuchen.lucene;

import org.apache.commons.io.FilenameUtils;
import org.apache.log4j.Logger;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.*;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Sort;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Jack Q
 *
 */
public class LuceneHelper {

    private final static Logger LOG = Logger.getLogger(LuceneHelper.class);

    private String indexPath; //lucene索引存放的目录文件夹

    public static LuceneHelper init(String indexDir) throws IOException {//第一步初始化
        LuceneHelper helper = new LuceneHelper();
        indexDir = FilenameUtils.normalize(indexDir);
        File file = new File(indexDir);
        if(!file.exists() || !file.isDirectory()){
           throw  new FileNotFoundException("索引目录不存在："+indexDir);
        }
        if(!indexDir.endsWith(File.separator))
            indexDir += File.separator;
        helper.indexPath = indexDir;
        return helper;
    }

    //IndexWriter
    private IndexWriter getWriter(Class<? extends Searchable> objClass) throws IOException{
        Directory dir = FSDirectory.open(new File(indexPath+objClass.getSimpleName()));
        IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_10_4,LuceneConstant.analyzer);
        config.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
        return new IndexWriter(dir,config);
    }

    //IndexSearcher
    private IndexSearcher getSearcher(Class<? extends  Searchable> objClass) throws IOException{
        Directory dir = FSDirectory.open(new File(indexPath+objClass.getSimpleName()));
        IndexReader reader = DirectoryReader.open(dir);
        return new IndexSearcher(reader);
    }

    //多索引资料库搜索
    private IndexSearcher getSearchers(List<Class<? extends  Searchable>> objClasses) throws IOException{
        IndexReader[] readers = new IndexReader[objClasses.size()];
        int idx = 0;
        for(Class<? extends  Searchable> objClass : objClasses){
            Directory dir = FSDirectory.open(new File(indexPath+objClass.getSimpleName()));
            readers[idx++] = DirectoryReader.open(dir);
        }
        return new IndexSearcher(new MultiReader(readers,true));
    }


    //###############################################索引创建更新删除#######################################
    //#####################################################################################################

    /**
     * 创建索引
     * @param objs
     * @return
     * @throws IOException
     */
    public int add(List<? extends  Searchable> objs) throws IOException {
        if(null==objs || objs.size()==0)
            return 0;
        int doc_count = 0;
        IndexWriter writer = getWriter(objs.get(0).getClass());
        try{
            for(Searchable obj : objs){
                Document doc = DocumentHelper.obj2doc(obj);
                writer.addDocument(doc);
                doc_count++;
            }
            writer.commit();
        }finally {
            writer.close();
            writer = null;
        }
        return doc_count;
    }
    /**
     * 批量删除索引
     * @param objs
     * @throws IOException
     */
    public int delete(List<? extends Searchable> objs) throws IOException {
        if (objs == null || objs.size() == 0)
            return 0;
        int doc_count = 0;
        IndexWriter writer = getWriter(objs.get(0).getClass());
        try{
            for (Searchable obj : objs) {
                writer.deleteDocuments(new Term("id", String.valueOf(obj.id())));
                doc_count++;
            }
            writer.commit();
        }finally{
            writer.close();
            writer = null;
        }
        return doc_count;
    }

    /**
     * 批量更新索引
     * @param objs
     * @throws IOException
     */
    public void update(List<? extends Searchable> objs) throws IOException {
        delete(objs);
        add(objs);
    }


    //###############################################索引检索##############################################
    //#####################################################################################################

    /**
     * 多库搜索
     * @param objClasses
     * @param query
     * @param filter
     * @param sort
     * @param page
     * @param count
     * @return
     * @throws IOException
     */
    public List<Searchable> find(List<Class<? extends Searchable>> objClasses, Query query, Filter filter, Sort sort, int page, int count) throws IOException {
        IndexSearcher searcher = getSearchers(objClasses);
        return SearchHelper.find(searcher, query, filter, sort, page, count);
    }

    /**
     * 单库搜索
     * @param objClass
     * @param query
     * @param filter
     * @param sort
     * @param page
     * @param count
     * @return
     * @throws IOException
     */
    public List<Long> find(Class<? extends Searchable> objClass, Query query, Filter filter, Sort sort, int page, int count) throws IOException {
        IndexSearcher searcher = getSearcher(objClass);
        List<Searchable> results = SearchHelper.find(searcher, query, filter, sort, page, count);
        List<Long> ids = new ArrayList<Long>();
        for(Searchable obj : results){
            if(obj != null)
                ids.add(obj.id());
        }
        return ids;
    }

    /**
     * 多库搜索
     * @param objClasses
     * @param query
     * @param filter
     * @return
     * @throws IOException
     */
    public int count(List<Class<? extends Searchable>> objClasses, Query query, Filter filter) throws IOException {
        IndexSearcher searcher = getSearchers(objClasses);
        return SearchHelper.count(searcher, query, filter);
    }

    /**
     * 搜索
     * @param objClass
     * @param query
     * @param filter
     * @return
     * @throws IOException
     */
    public int count(Class<? extends Searchable> objClass, Query query, Filter filter) throws IOException {
        IndexSearcher searcher = getSearcher(objClass);
        return SearchHelper.count(searcher, query, filter);
    }

}
